﻿using System;
using System.Globalization;
using System.Text;
using SSG.Tools;

namespace SSG.Model
{
    /// <summary>
    /// Holding
    /// </summary>
    public class Holding : Fix
    {
        /// <summary>
        /// Holding turn
        /// </summary>
        public enum Turn
        {
            Right,
            Left
        }

        /// <summary>
        /// Legtime in seconds
        /// </summary>
        public int LegtimeSec { get; set; }
        /// <summary>
        /// 
        /// </summary>
        public string LegtimeUnitSec { get { return this.LegtimeSec.UnitSeconds(); } }

        /// <summary>
        /// Inbound heading
        /// </summary>
        public double InboudHeadingMagneticDeg { get; set; }

        /// <summary>
        /// Inbound heading degrees
        /// </summary>
        public string InboudHeadingMagneticUnitDegrees { get { return this.InboudHeadingMagneticDeg.UnitDeg(); } }

        /// <summary>
        /// Holding turn direction
        /// </summary>
        public Turn HoldingTurn { get; set; }

        /// <summary>
        /// Holding
        /// </summary>
        /// <param name="name"></param>
        /// <param name="canoncialName"></param>
        /// <param name="description"></param>
        /// <param name="lat"></param>
        /// <param name="lng"></param>
        public Holding(string name, string canoncialName = null, string description = null, double lat = 0, double lng = 0) : base(name, canoncialName, description, lat, lng)
        {
            // code goes here
        }

        /// <summary>
        /// "Clone constructor"
        /// </summary>
        /// <param name="otherFix"></param>
        public Holding(Fix otherFix) : base(otherFix)
        {
            Holding otherHolding = otherFix as Holding;
            if (otherHolding == null) return;
            this.HoldingTurn = otherHolding.HoldingTurn;
            this.InboudHeadingMagneticDeg = otherHolding.InboudHeadingMagneticDeg;
        }

        /// <summary>
        /// From an PMDG FMC line such as
        /// APPROACH LLZ26 ... RTTNB 9500 HOLD AT FIX_RTTNB RIGHT TURN INBOUNDCOURSE 226 ALT 9500 LEGTIME 1
        /// </summary>
        /// <param name="line"></param>
        /// <param name="correspondingFixpoint"></param>
        /// <returns></returns>
        public static Holding FromPmdgFormat(string line, Fix correspondingFixpoint)
        {
            // checks
            if (string.IsNullOrEmpty(line)) return null;
            int haIndex = line.IndexOf("HOLD AT ", StringComparison.CurrentCultureIgnoreCase);
            if (haIndex < 0) return null;
            if (correspondingFixpoint == null) throw new ArgumentNullException("correspondingFixpoint");

            string holdAtPart = line.Substring(haIndex).ToUpperInvariant();
            Holding holding = new Holding(correspondingFixpoint);

            // get turn type
            if (holdAtPart.Contains("RIGHT TURN"))
                holding.HoldingTurn = Turn.Right;
            else if (holdAtPart.Contains("LEFT TURN"))
                holding.HoldingTurn = Turn.Left;
            else
                throw new FmcParseException("Unknow turn type") {Content = holdAtPart};

            // parse other parts
            string[] parts = holdAtPart.Split(' ');
            for (int p = 0; p < parts.Length; p++) {
                string part = parts[p];
                if ("INBOUNDCOURSE".Equals(part)) {
                    double inbound;
                    if (!Double.TryParse(parts[p++], NumberStyles.Float | NumberStyles.AllowThousands, Coordinates.ParseCulture, out inbound))
                        throw new FmcParseException("Cannot parse inbound course") {Content = holdAtPart};
                    holding.InboudHeadingMagneticDeg = inbound;
                }
                else if ("ALT".Equals(part)) {
                    double alt;
                    if (!Double.TryParse(parts[p++], NumberStyles.Float | NumberStyles.AllowThousands, Coordinates.ParseCulture, out alt))
                        throw new FmcParseException("Cannot parse altitude") {Content = holdAtPart};
                    holding.AltitudeRestriction = new Altitude(alt, Altitude.AltitudeMode.Msl, Altitude.AltitudeModifier.Exact);
                }
                else if ("LEGTIME".Equals(part)) {
                    double legtime;
                    if (!Double.TryParse(parts[p++], NumberStyles.Float | NumberStyles.AllowThousands, Coordinates.ParseCulture, out legtime))
                        throw new FmcParseException("Cannot parse legtime") {Content = holdAtPart};
                    holding.LegtimeSec = (int) Math.Round(legtime*60.0);
                }
            }
            return holding;
        }

        /// <summary>
        /// Clone
        /// </summary>
        /// <returns></returns>
        public override object Clone()
        {
            return new Holding(this);
        }

        /// <summary>
        /// Meaningful representation
        /// </summary>
        /// <returns></returns>
        public override string ToString()
        {
            StringBuilder sb = new StringBuilder();
            sb.Append("Inbound: ");
            sb.Append(this.InboudHeadingMagneticUnitDegrees);
            sb.Append(" Legtime: ");
            sb.Append(this.LegtimeUnitSec);
            sb.Append(" Turn: ");
            sb.Append(this.HoldingTurn.ToString());
            return sb.ToString();
        }
    }
}